function Result(code, msg, data, resultType){
    this.code = code;
    this.msg = msg;
    this.data = data;
    this.resultType = resultType;
};
const local = {
    MANUAL_REPLY: "ManualReply",
    notExistInterface: result(200, "不存在该接口"),
    builderInterface: result(200, "接口开发中"),
    continuouQueryDelayPlusResult,
    result,
    /**
     * 错误
     * 支持多次封装时不会嵌套更改
     * @param {Object} data 数据
     * @param {String} msg 消息
     * @param {Number} code 返回码
     * @returns {{code: "代码", msg: "消息", data: "数据"}} 
     */
    error(msg, data, code) {
        return result(code || 500, msg, data)
    },
    /**
     * 失败
     * 支持多次封装时不会嵌套更改
     * @param {Object} data 数据
     * @param {String} msg 消息
     * @param {Number} code 返回码
     * @returns {{code: "代码", msg: "消息", data: "数据"}} 
     */
    failure(msg, data, code) {
        return result(code || 400, msg || "失败", data)
    },
    /**
     * 成功
     * 支持多次封装时不会嵌套更改
     * @param {Object} data 数据
     * @param {String} msg 消息
     * @param {Number} code 返回码
     * @returns {{code: "代码", msg: "消息", data: "数据"}} 
     */
    succeed(msg, data, code) {
        return result(code || 200, msg || "成功", data)
    },
    /**
     * 自动响应数据
     * 1. 如果数据是一个对象，而且携带有“数字类型”参数 code，那么会把 code设置成状态码，code只接受整数
     * 2. 参数多个就会封装成数组返回
     * 3. 数据只有一个则直接返回
     * @param {Response} res 响应体对象
     * @param {Object...} 可变长参数
     */
    send(res, data){
        if(2 < arguments.length) {
            // 封装成数组
            let re = [];
            for (let i = 1; i < arguments.length; i++) {
                re.push((arguments[i]));
            }
            data = re;
        }
        if(data != null) {
            let code = parseInt(data.code);
            if(!isNaN(code)){
                if(code < 400) {
                    // 状态码过小
                    if(code < 100) code = 101;
                } else if(1000 <= code){
                    // 状态码过大
                    code = 998;
                }
                res.status(code);
            }
        }
        
        let originData = JSON.stringify(data);
        if(clearStack(data)) {
            console.log("已清清除异常栈信息", JSON.parse(originData));
        }
        try{
            res.send(data);
        }catch(err){
            console.error("发送数据异常！", err);
        }
    },
}
module.exports = local;

/**
 * 如果参数中包含栈信息则清空栈信息（删除 stack 属性）
 * 如果参数是一个数组，那么会遍历数组去查看是否有对象存在栈信息 
 * 如果存在 data 属性也会去查看 data 
 * @param {Object} p 参数 
 * @returns {Boolean} 是否清除过
 */
function clearStack(p){
    let re = false;
    if(typeof p == "object") {
        if(p instanceof Array) {
            // 遍历数组
            p.forEach(e=>{
                if(clearStack(e)) re = true;
            })
        } else if(p.data) {
            // 检查 data 
            if(clearStack(p.data)) re = true;
        } else if(p != null && p.stack){
            // 清除属性
            delete p.stack;
            re = true;
        }
    }
    return re;
}
/**
 * 返回值，发送给客户端的数据格式
 * 支持多次封装时不会嵌套更改
 * @param {Number} code 返回码
 * @param {String} msg 消息
 * @param {Object} data 数据
 * @returns {{code: "代码", msg: "消息", data: "数据"}} 
 */
function result(code, msg, data) {
    if(data instanceof Result) {
        data.code = code;
        data.msg = msg;
        data.resultType = "cli";
        return data;
    }
    if(data instanceof Error) {
        data = {
            message: data.message,
            stack: data.stack
        }
    }
    return new Result(code, msg, data, "cli");
}
/**
 * 循环查询的返回值格式，如果不存在 err信息则不会添加
 * @param {Object} data 数据原对象，需要属性 {data|body, err|error}
 * @param {Object} 返回数据格式 {data, err} 
 */
function continuouQueryDelayPlusResult(data) {
    let re = {data: data.data || data.body};
    let err = data.err || data.error;
    if(err) {
        if(err instanceof Error) {
            re.err = {
                message: err.message,
                stack: err.stack,
            };
        } else {
            re.err = err;
        }
    }
    return re;
}